/*******************************************************************
 *   > File Name: start.S
 *   > Author: fly
 *   > Mail: 1358326274@qq.com
 *   > Create Time: 2020年07月17日 星期五 07时56分19秒
 ******************************************************************/
/*=================================================================
 * 汇编点亮led灯：对应GPIO口输出低电平，点亮LED
 * D22->GPJ0_3
 * D23->GPJ0_4
 * D24->GPJ0_5
 * D25->PWMOUT1/GPD0_1
 *================================================================*/
#define GPD0CON         0xE02000A0
#define GPD0DAT         0xE02000A4
#define GPD0PUD         0xE02000A8

#define GPJ0CON         0xE0200240
#define GPJ0DAT         0xE0200244
#define GPJ0PUD         0xE0200248

#define PS_HOLD_CONTORL 0xE010E81C
#define WTCON           0xE2700000
#define SVC_STACK       0xD0037D80

//#define CONFIG_SYS_ICACHE_OFF   1

.global _start
_start:
    //给5v电源置锁
    //LDR指令：从内存中将1个32位的字读取到目标寄存器中
    //STR指令：将1个32位的字数据写入到指令中指定的内存单元中
    //ORR指令：
    ldr r0,=PS_HOLD_CONTORL     //r0=0xE010E81C
    ldr r1,[r0]                 //将r0地址处的数据读出，保存到r1中（零偏移）
    orr r1,r1,#0x300            //设置r1的第8、9位，其他位保持不变
    orr r1,r1,#0x1              //设置r1的第1位，其他位保持不变
    str r1,[r0]                 //将r1中的内容传输到r0中数指定的地址内存中去

    //关看门狗
    ldr r0, =WTCON
    mov r1, #0
    str r1, [r0]

    //开/关iCache
    // MRC指令:从协处理器寄存器传数据到ARM寄存器
    // MCR指令:从ARM寄存器传数据到协处理器寄存器
    mrc p15, 0, r0, c1, c0, 0
    #ifdef CONFIG_SYS_ICACHE_OFF
    bic r0, r0, #0x00001000     @ clear bit 12 (I) I-Cache
    #else
    orr r0, r0, #0x00001000     @ set bit 12 (I) I-Cache
    #endif
    mcr p15, 0, r0, c1, c0, 0

    //设置栈，以便调用c函数
    ldr sp, =SVC_STACK

led_init:
    /* LED初始化 */
    //把GPIO设置输出模式
    ldr r0,=0x11111111
    ldr r1,=GPJ0CON
    str r0, [r1]                //把GPJ0所有的IO设置为输出模式

    ldr r0,=0x00000010
    ldr r1,=GPD0CON
    str r0,[r1]                 //把GPD0_1设置为输出模式

led_run:
    /* LED流水灯 */
    // 第1步：点亮LED1，其他熄灭
    ldr r0, =~(1<<3)            //r0=0xFFFFFFF7
    ldr r1, =GPJ0DAT            //r1=0xE0200244
    str r0, [r1]
    //熄灭LED4
    ldr r0, =~(0<<1)            //r0=0xFFFFFFFF
    ldr r1, = GPD0DAT
    str r0, [r1]
    bl delay

    // 第2步：点亮LED2，其他熄灭    
    ldr r0, =~(1<<4)            //r0=0xFFFFFFEF
    ldr r1, =GPJ0DAT
    str r0, [r1]
    bl delay

    // 第3步：点亮LED3，其他熄灭    
    ldr r0, =~(1<<5)            //r0=0xFFFFFFDF
    ldr r1, =GPJ0DAT
    str r0, [r1]
    bl delay

    //熄灭LED3/4/5，点亮LED4
    ldr r0, = ((1<<3)|(1<<4)|(1<<5))
    ldr r1, =GPJ0DAT
    str r0, [r1]
    ldr r0, =~(1<<1)            //r0=0xFFFFFFFD
    ldr r1, = GPD0DAT
    str r0, [r1]
    bl delay

    bl led_run

half:
    b half

    /* 延时函数：delay*/
delay:
    ldr r2,=9000000
    ldr r3,=0x0
delay_loop:
    //SUB指令：从寄存器Rn中减去shifter_operand表示的数值，
    //并将结果保存在目标寄存器Rd中，并根据指令的执行结果
    //设置CPSR中的相应标志位
    //SUB {<cond>} {s} <Rd>,<Rn>,<shifter_operand>
    sub r2,r2,#1                //r2 = r2 - 1
    //CMP指令:使用寄存器Rn的值减去shifter_operand的值，
    //根据操作的结果更新CPSR中相应的条件标志位，以便后面
    //的指令根据相应的条件标志位来判断是否执行
    //CMP {<cond>} <Rn>,<shifter_operand>
    cmp r2, r3
    bne delay_loop
    mov pc,lr
